Flutter 内嵌原生视图能力

在 Flutter 开发中,有一些原生开发的视图(Android/iOS),这些视图在 Flutter 中该如何使用呢?

有一种直观的想法,直接用 Flutter 开发一遍不就行了吗?

这是最理想的方案。然而,很多时候,原生视图本身比较复杂,比如 WebView、地图、播放器、游戏引擎,我们很难用 Flutter 将其开发一遍。

因此,另外一种想法,能否将这些原生视图“嵌”入 Flutter 当中,实现复用呢?

答案是支持,Flutter 通过平台视图(Platform View)机制,支持将原生视图嵌入 Flutter。

这一特性,通常用于复用复杂视图,比如 WebView、播放器、地图、游戏引擎画面等。

因为同时涉及到 Android、iOS、Flutter 三个平台,因此需要开发者具备相关平台的知识。

在本文中,对 PlatformView 进行综合介绍。在本章后续文章中,将从使用一直深入到实现原理,做到彻底掌握。后续文章可从侧边栏中浏览。


Android 嵌原生能力

说到 Flutter 的 Platform View 能力,首先想聊的是 Android 平台。这项能力在 Android 上的发展十分曲折,一直以来效果都不理想,受到了诟病。

关于这段曲折发展,具体可参考:《Flutter III 之你不知道的 PlatformView 的混乱之治

“目前 Flutter 对于嵌原生支持非常混乱。目前3套方案,TLHC、HC、VD 都不是最优解。存在各种兜底策略、历史包袱,因此遇到问题非常难以排查。”


Android 下3种渲染模式

目前,在 Flutter Platform View 在 Android 下,存在 3 套渲染模式,按照代际来分:

代际 名称 介绍 优点 缺点
虚拟显示模式
Virtual displays
VD
基于 Android VirtualDisplay 机制
将原生视图渲染为纹理
使用 Flutter Texture 渲染
不耦合 Flutter 渲染流水线 容易有触摸和软键盘兼容性问题
GPU-CPU-GPU 多次内存拷贝,性能开销
混合集成模式
Hybrid composition
HC
将原生视图附加到视图层次结构中
Flutter 视图分层渲染
键盘处理、无障碍开箱即用 Android 10 以前的版本,内存占用变大,绘制性能降低
存在线程竞争问题,容易出现闪烁和卡顿
Texture Layer Hybrid Composition
TLHC
FrameLayout 代理 onDraw,替换掉 child 原生控件 Canvas
Flutter 3.0 版本引入
对普通原生视图支持较好 不支持 SurfaceView(播放器、地图)
TextureView 支持也不完备,并不总是能正常更新
对于封装 Platform View 的开发者来说,需要根据具体场景,选择适合的模式。同时,为了考虑兼容性,还需要兼容其它几种模式。

模式并存

在 Flutter 中,3 种模式能并存吗?

由于我尚未对 TLHC 模式开展调研。这里我仅给出部分结论:VD 和 HC 两者是可以并存的


iOS 下的渲染模式

在 iOS 下仅有一种渲染模式——混合集成模式(Hybrid composition,HC)。

该模式在 iOS 下工作稳定,比较理想,不存在 Android 下这种混乱的情况。

为什么会这样?根据我粗浅的理解,iOS 系统的架构历史悠久,设计更加合理、强大。


附录

以下是我的一些杂乱的草稿,后续会被吸收到其它章节中。

代码实现

Flutter 内嵌原生视图 Android 端接入实现

上面从概念上进行了介绍,那如何在 Android 平台下进行代码实现呢?在这篇笔记中记录了对应的代码实现。以及 Flutter 3 之前与之后,对 3 中模式的兼容方式的介绍。点击阅读…

GitHub Issues

性能

在 Flutter 中,平台视图的使用会带来性能上的权衡。

例如,在一个典型的 Flutter 应用中,Flutter UI 是在一个专用的光栅线程上组合的。这使得 Flutter 应用可以快速运行,因为主平台线程很少被阻塞。

当使用混合组合渲染平台视图时,Flutter UI 是从平台线程组合的,这与处理操作系统或插件消息等其他任务竞争资源。

在 Android 10 之前,混合组合模式会将每一帧 Flutter 帧从图形内存复制到主内存,然后再复制回 GPU 纹理。由于这种复制是逐帧发生的,整个 Flutter UI 的性能可能会受到影响。在 Android 10 或更高版本中,图形内存只需复制一次。

另一方面,虚拟显示使原生视图的每个像素都通过额外的中间图形缓冲区流动,这会消耗图形内存和绘图性能。

对于复杂情况,有一些技术可以用来缓解这些问题。

例如,当 Dart 中发生动画时,你可以使用占位符纹理。换句话说,如果在渲染平台视图时动画变慢,那么可以考虑对原生视图进行截图,并将其作为纹理进行渲染。

在使用平台视图时,性能会有影响。具体参见《性能》。

Hybrid composition

Virtual displays

应用场景

WebView

WebView 是 Flutter 内嵌原生视图能力最常见的场景。WebView 是移动开发中最常使用的控件之一,也是最为复杂的控件之一。在 Flutter 开发中,也需要 WebView 能力。社区中常见的方案,它利用 PlatformView 机制,对 Android、iOS 的 WebView 进行封装,封装为一个 Flutter 组件。开发者在使用时,如同使用纯 Flutter 组件一般,而在底层,是嵌入了原生 WebView 视图能力。

1.1 使用 Flutter webview_flutter 库引入 WebView 能力

webview_flutter 是由 Google 官方团队开发的 Flutter WebView,也是社区中的热门选择方案。请参见这篇笔记

Flutter webview_flutter Android 端实现原理

PlatformView 在 Android 下兼容性问题较多,如果你对 Android 端的实现感兴趣,请参见这篇笔记

Flutter WebView 库梳理

除了 webview_flutter 之外,社区中还包含许多第三方开发者的实现,其中不乏高质量者也非常热门。具体可参见这篇笔记

常见场景

WebView

地图

根据《Flutter 工程化框架选择 — 混合开发的摸爬滚打 · GitBook》不同地图的实现策略:

类型 策略
高德 3.0 以下 Virtual displays,3.0 以上 TextureLayer
华为 3.0 以下 Hybrid composition,3.0 以上 Hybrid composition 或者 Texture Layer Hybrid Composition
百度 3.0 以下 Virtual displays,3.0 Texture Layer Hybrid Composition,3.0 以上 Virtual displays 或者 Texture Layer Hybrid Composition
相关库:

网络资源

platform view:

iOS:

virtual display:

Hybrid Composition:

兼容性:

GitHub Issues:

StackOverflow:

其他问题反馈:

Flutter WebView:

地图:


本文作者:Maeiee

本文链接:Flutter 内嵌原生视图能力

版权声明:如无特别声明,本文即为原创文章,版权归 Maeiee 所有,未经允许不得转载!


喜欢我文章的朋友请随缘打赏,鼓励我创作更多更好的作品!